#include <assert.h>
#include <string.h>
#include <sys/time.h>

#include "tcpserver.hpp"

/***************************************************acceptclient*********************************************************************/
static void check_sockname(struct sockaddr *addr, const char *compare_ip, int compare_port,
                           char *client_ip, uint16_t *client_port)
{
    struct sockaddr_in check_addr = *(struct sockaddr_in *)addr;
    struct sockaddr_in compare_addr;
    char check_ip[17];

    uv_ip4_addr(compare_ip, compare_port, &compare_addr);
    uv_ip4_name(&check_addr, (char *)check_ip, sizeof(check_ip));

	if (check_addr.sin_family == AF_INET) {
		printf("src sin_family is AF_INET.\n");
	}
 
	if (compare_addr.sin_family == AF_INET) {
		printf("compare sin_family is AF_INET.\n");
	}
 
	/* Check if the ip matches */
	if (memcmp(&check_addr.sin_addr, &compare_addr.sin_addr,
			sizeof(compare_addr.sin_addr)) == 0) {
		printf("ip matches.\n");
	}


    printf("accept: %s:%d\n", check_ip, ntohs(check_addr.sin_port));
    memcpy(client_ip, check_ip, sizeof(check_ip));
    *client_port = ntohs(check_addr.sin_port);
}

acceptclient::acceptclient(uv_loop_t *ploop, uv_stream_t *server, std::string server_ip, uint16_t server_port)
{
    int32_t iret = 0;

    this->loop = ploop;

    // this->rbuff = new uint8_t[TCP_RECV_BUFF_SIZE];
    this->rbuff = (uint8_t *)malloc(TCP_RECV_BUFF_SIZE);
    this->rbuffIn = 0;
    this->rbuffOut = 0;

    // this->uvRbuf.base = new char[TCP_RECV_UVBUFF_SIZE];
    this->uvRbuf.base = (char *)malloc(TCP_RECV_UVBUFF_SIZE);
    this->uvRbuf.len = TCP_RECV_UVBUFF_SIZE;

    // this->sbuff = new uint8_t[TCP_SEND_BUFF_SIZE];
    this->sbuff = (uint8_t *)malloc(TCP_SEND_BUFF_SIZE);
    this->sbuffIn = 0;
    this->sbuffOut = 0;

    this->serverIP = server_ip;
    this->serverPort = server_port;

    do
    {
        iret = uv_mutex_init(&this->rMutex);
        if (iret)
        {
            PlayerInfo("acceptclient uv_mutex_init rMutex", iret);
            break;
        }

        iret = uv_mutex_init(&this->sMutex);
        if (iret)
        {
            PlayerInfo("acceptclient uv_mutex_init sMutex", iret);
            break;
        }


        iret = uv_timer_init(this->loop, &this->sendTimer);
        if (iret)
        {
            PlayerInfo("acceptclient uv_timer_init sendTimer", iret);
            break;
        }

        iret = uv_async_init(this->loop, &this->sendAsync, sAcceptSendAsync);
        if (iret)
        {
            PlayerInfo("acceptclient uv_async_init sendAsync", iret);
            break;
        }

        iret = uv_tcp_init(this->loop, &this->acceptHandle);
        if (iret)
        {
            PlayerInfo("acceptclient uv_tcp_init", iret);
            break;
        }

        iret = uv_tcp_nodelay(&this->acceptHandle, 1);
        if (iret)
        {
            PlayerInfo("addTcpClient uv_tcp_nodelay", iret);
            break;
        }

        iret = uv_tcp_keepalive(&this->acceptHandle, 1, 60);
        if (iret)
        {
            PlayerInfo("addTcpClient uv_tcp_keepalive", iret);
            break;
        }

        iret = uv_accept((uv_stream_t *)server, (uv_stream_t *)&this->acceptHandle);
        if (iret)
        {
            PlayerInfo("acceptclient uv_accept", iret);
            break;
        }

        struct sockaddr peername;
        int namelen = sizeof(peername);
        struct sockaddr_in compare_addr;
        char client_ip[17];
        uint16_t client_port;
        uv_tcp_getpeername(&this->acceptHandle, &peername, &namelen);
        check_sockname(&peername, server_ip.c_str(), server_port, client_ip, &client_port);
        this->acceptIP = client_ip;
        this->acceptPort = client_port;
        fprintf(stdout, "newAcceptClient ip = %s, port = %d\n", client_ip, client_port);

        iret = uv_read_start((uv_stream_t *)&this->acceptHandle, acceptclient::sAcceptAllocBufferForRecv, acceptclient::sAcceptAfterRecv);
        if (iret)
        {
            PlayerInfo("AcceptConnection uv_read_start", iret);
            break;
        }

        this->isConnect = true;
        this->acceptHandle.data = this;
        this->sendTimer.data = this;
        this->sendAsync.data = this;
        this->parent = server->data;

        this->acceptStartSend();
    } while (0);
}

acceptclient::~acceptclient()
{
    // this->acceptStopSend();

    // delete[] this->uvRbuf.base;                                  // 缓存区在close之后释放
    // delete[] this->rbuff;
    // delete[] this->sbuff;
    // free(this->uvRbuf.base);
    // free(this->rbuff);
    // free(this->sbuff);

    uv_mutex_destroy(&this->rMutex);
    uv_mutex_destroy(&this->sMutex);
}

std::string acceptclient::acceptGetIP()
{
    return this->acceptIP;
}

uint16_t acceptclient::acceptGetPort()
{
    return this->acceptPort;
}

#if 0
int32_t acceptclient::acceptRecvData(uint8_t *buff, int32_t buff_len)
{
    int32_t len = 0;

    assert(buff);
    assert(buff_len > 0);

    uv_mutex_lock(&this->rMutex);
    if (this->rbuffIn != this->rbuffOut)
    {
        if ((this->rbuffOut + buff_len) <= this->rbuffIn)
        {
            memcpy(buff, this->rbuff + this->rbuffOut, buff_len);
            len = buff_len;
            this->rbuffOut += buff_len;

            if (this->rbuffOut == this->rbuffIn)
            {
                this->rbuffOut = 0;
                this->rbuffIn = 0;
            }
        }
    }
    uv_mutex_unlock(&this->rMutex);

    return len;
}
#endif

int32_t acceptclient::acceptRecvData(uint8_t *buff, int32_t buff_len)
{
    uint8_t *ptr = this->rbuff + this->rbuffOut;
    uint16_t frameLen = 0;

    assert(buff);
    assert(buff_len > 0);

    uv_mutex_lock(&this->rMutex);
    if (this->rbuffIn != this->rbuffOut)
    {
        if (((ptr[0] == 0xD2) && (ptr[1] == 0x8C)) ||
            ((ptr[0] == 0x4D) && (ptr[1] == 0x73)))
        {
            frameLen = htons(*(uint16_t *)(ptr + FRAME_OFFSET_DATALEN)) + 18;
            if ((this->rbuffOut + frameLen) <= this->rbuffIn)
            {
                memcpy(buff, ptr, frameLen);
                this->rbuffOut += frameLen;
                memset(ptr, 0x00, frameLen);
                if (this->rbuffOut == this->rbuffIn)
                {
                    this->rbuffIn = 0;
                    this->rbuffOut = 0;
                }
            }
            else
                frameLen = 0;
        }
        else
        {
            this->rbuffOut++;
        }
    }
    uv_mutex_unlock(&this->rMutex);
    return frameLen;
}


int32_t acceptclient::acceptSendData(uint8_t *sdata, int32_t sdata_len)
{
    int32_t ret = 0;

    assert(sdata);
    assert(sdata_len > 0);

    if (this->isConnect)
    {
        uv_mutex_lock(&this->sMutex);
        if ((this->sbuffIn + sdata_len) <= TCP_SEND_BUFF_SIZE)
        {
            memcpy(this->sbuff + this->sbuffIn, sdata, sdata_len);
            this->sbuffIn += sdata_len;

            ret = sdata_len;
        }
        uv_mutex_unlock(&this->sMutex);
    }

    return ret;
}

int32_t acceptclient::acceptGetRemainSpace()
{
    int32_t ret = 0;

    uv_mutex_lock(&this->rMutex);
    ret = TCP_RECV_BUFF_SIZE - this->rbuffIn;
    uv_mutex_unlock(&this->rMutex);

    return ret;
}

void acceptclient::sAcceptAllocBufferForRecv(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
{
    class acceptclient *tmpAccept = (class acceptclient *)handle->data;
    class tcpserver *tmpServer = (class tcpserver *)tmpAccept->parent;

    assert(tmpAccept);
    assert(tmpServer);

    *buf = tmpAccept->uvRbuf;
}

void acceptclient::sAcceptAfterRecv(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf)
{
    class acceptclient *tmpAccept = (class acceptclient *)client->data;
    class tcpserver *tmpServer = (class tcpserver *)tmpAccept->parent;
    unsigned long long now = 0;

    if (nread > 0)
    {
        // sysGetCurPts(&now);
        uv_mutex_lock(&tmpAccept->rMutex);
        if ((tmpAccept->rbuffIn + nread) <= TCP_RECV_BUFF_SIZE)
        {
            memset(tmpAccept->rbuff + tmpAccept->rbuffIn, 0x00, nread);
            memcpy(tmpAccept->rbuff + tmpAccept->rbuffIn, buf->base, nread);
            tmpAccept->rbuffIn += nread;
        }
        // printf("time %lld us, recv %ld, all %u\n", now, nread, tmpAccept->rbuffIn);
        uv_mutex_unlock(&tmpAccept->rMutex);
    }
    else if (nread < 0)
    {
        printf("close and delete acceptClient\n");
        tmpAccept->acceptStopSend();
        uv_close((uv_handle_t *)client, sAcceptAfterClose);
        // tmpServer->tsDeleteAcceptClient(client, tmpAccept->acceptIP, tmpAccept->acceptPort);     // 这个函数似乎会导致服务端程序崩溃
    }
}

void acceptclient::sAcceptAfterClose(uv_handle_t *handle)
{
    class acceptclient *tmpAccept = (class acceptclient *)handle->data;

    tmpAccept->isConnect = false;

    tmpAccept->acceptIP = "";
    tmpAccept->acceptPort = 0;
    free(tmpAccept->uvRbuf.base);                           // close 之后释放缓存区，见tmpServer->tsDeleteAcceptClient的注释
    tmpAccept->uvRbuf.base = NULL;
    free(tmpAccept->rbuff);
    tmpAccept->rbuff = NULL;
    free(tmpAccept->sbuff);
    tmpAccept->sbuff = NULL;
}

void acceptclient::sAcceptSendTimer(uv_timer_t *handle)
{
    class acceptclient *tmpAccept = (class acceptclient *)handle->data;

    if (tmpAccept->isConnect)
        uv_async_send(&tmpAccept->sendAsync);
}

void acceptclient::sAcceptSendAsync(uv_async_t *handle)
{
    class acceptclient *tmpAccept = (class acceptclient *)handle->data;

    uv_buf_t bufs[CHUNKS_PER_WRITE];
    uv_write_t *write_reqs = &tmpAccept->write_reqs;
    int32_t i = 0;

    char *ptr = (char *)tmpAccept->sbuff + tmpAccept->sbuffOut;
    uint32_t len = 0;

    uv_mutex_lock(&tmpAccept->sMutex);
    if ((tmpAccept->isConnect) && (tmpAccept->sbuffIn != tmpAccept->sbuffOut))
    {
        for (i = 0; i < CHUNKS_PER_WRITE; )
        {
            if ((tmpAccept->sbuffOut + TCP_SEND_UVBUFF_SIZE) <= tmpAccept->sbuffIn)
            {
                len = TCP_SEND_UVBUFF_SIZE;
            }
            else
            {
                len = tmpAccept->sbuffIn - tmpAccept->sbuffOut;
            }

            bufs[i] = uv_buf_init(ptr, len);
            i++;

            tmpAccept->sbuffOut += len;
            ptr += len;
            if (tmpAccept->sbuffOut == tmpAccept->sbuffIn)
            {
                tmpAccept->sbuffOut = 0;
                tmpAccept->sbuffIn = 0;
                break;
            }
        }

        if (i > 0)
        {
            write_reqs->data = tmpAccept;
            uv_write(write_reqs, (uv_stream_t *)&tmpAccept->acceptHandle, bufs, i, acceptclient::sAcceptAfterSend);
        }
    }
    else if  ((tmpAccept->isConnect) && (tmpAccept->sbuffIn == tmpAccept->sbuffOut))
    {
        tmpAccept->acceptStartSend();
    }
    uv_mutex_unlock(&tmpAccept->sMutex);
}

void acceptclient::sAcceptAfterSend(uv_write_t *req, int status)
{
    class acceptclient *tmpAccept = (class acceptclient *)req->data;

    if (status == 0)
    {
        tmpAccept->acceptStartSend();
    }
    else
    {
        PlayerInfo("sAcceptAfterSend ", status);
        tmpAccept->acceptStopSend();
    }
}

void acceptclient::acceptStartSend(void)
{
    this->repeatSendTime = 10;
    uv_timer_start(&this->sendTimer, acceptclient::sAcceptSendTimer, this->repeatSendTime, 0);
}

void acceptclient::acceptStopSend(void)
{
    this->repeatSendTime = 10;
    uv_timer_stop(&this->sendTimer);
}

/*****************************************************tcpserver*********************************************************************/
tcpserver::tcpserver(uv_loop_t *ploop, std::string server_ip, uint16_t server_port)
{
    int32_t iret = 0;

    this->loop = ploop;
    this->serverIP = server_ip;
    this->serverPort = server_port;

    do
    {
        iret = uv_mutex_init(&this->acceptMutex);
        if (iret)
        {
            PlayerInfo("tcpserver uv_mutex_init", iret);
            break;
        }

        iret = uv_tcp_init(this->loop, &this->serverHandle);
        if (iret)
        {
            PlayerInfo("tcpserver uv_tcp_init", iret);
            break;
        }

        iret = uv_tcp_nodelay(&this->serverHandle, 1);
        if (iret)
        {
            PlayerInfo("tcpserver uv_tcp_nodelay", iret);
            break;
        }

        iret = uv_tcp_keepalive(&this->serverHandle, 1, 60);
        if (iret)
        {
            PlayerInfo("tcpserver uv_tcp_keepalive", iret);
            break;
        }

        iret = uv_ip4_addr(server_ip.c_str(), server_port, &this->addr);
        if (iret)
        {
            PlayerInfo("tcpserver uv_ip4_addr", iret);
            break;
        }

        iret = uv_tcp_bind(&this->serverHandle, (const struct sockaddr *)&this->addr, 0);
        if (iret)
        {
            PlayerInfo("tcpserver uv_tcp_bind", iret);
            break;
        }

        iret = uv_listen((uv_stream_t *)&this->serverHandle, 128, AcceptConnection);
        if (iret)
        {
            PlayerInfo("tcpserver uv_listen", iret);
        }

        this->serverHandle.data = this;
        return;
    } while (0);
}

tcpserver::~tcpserver()
{
    uv_mutex_destroy(&this->acceptMutex);
}

int32_t tcpserver::tsDeleteAcceptClient(uv_stream_t *client, std::string accept_ip, uint16_t accept_port)
{
    class acceptclient *tmpAccept = (class acceptclient *)client->data;

    std::vector<class acceptclient *>::iterator iter;

    uv_mutex_lock(&this->acceptMutex);
    if (this->acceptclientVec.size() > 0)
    {
        for (iter = this->acceptclientVec.begin(); iter != acceptclientVec.end(); iter++)
        {
            if (((*iter)->acceptGetIP() == accept_ip) && ((*iter)->acceptGetPort() == accept_port))
            {
                delete (*iter);
                (*iter) = nullptr;
                acceptclientVec.erase(iter);
                printf("after delete acceptClient\n");
                break;
            }
        }
    }
    uv_mutex_unlock(&this->acceptMutex);

    // return this->acceptclientVec.size();
    return 0;
}

int32_t tcpserver::tsGetAcceptClientRecvData(std::string accept_ip, uint16_t accept_port, uint8_t *buff, int32_t buff_len)
{
    int32_t ret = 0;
    assert(buff);
    assert(buff_len > 0);

    std::vector<class acceptclient *>::iterator iter;
    uv_mutex_lock(&this->acceptMutex);
    if (this->acceptclientVec.size() > 0)
    {
        for (iter = this->acceptclientVec.begin(); iter != acceptclientVec.end(); iter++)
        {
            if (((*iter)->acceptGetIP() == accept_ip) && ((*iter)->acceptGetPort() == accept_port))
            {
                ret = (*iter)->acceptRecvData(buff, buff_len);
                break;
            }
        }
    }
    uv_mutex_unlock(&this->acceptMutex);

    return ret;
}

int32_t tcpserver::tsSetAcceptClientSendData(std::string accept_ip, uint16_t accept_port, uint8_t *sdata, int32_t sdata_len)
{
    int32_t ret = 0;

    assert(sdata);
    assert(sdata_len > 0);

    std::vector<class acceptclient *>::iterator iter;
    uv_mutex_lock(&this->acceptMutex);
    if (this->acceptclientVec.size() > 0)
    {
        for (iter = this->acceptclientVec.begin(); iter != acceptclientVec.end(); iter++)
        {
            if (((*iter)->acceptGetIP() == accept_ip) && ((*iter)->acceptGetPort() == accept_port))
            {
                ret = (*iter)->acceptSendData(sdata, sdata_len);
                break;
            }
        }
    }
    uv_mutex_unlock(&this->acceptMutex);

    return ret;
}

int32_t tcpserver::tsGetAcceptClientRemainSpace(std::string accept_ip, uint16_t accept_port)
{
    int32_t ret = 0;

    std::vector<class acceptclient *>::iterator iter;
    if (this->acceptclientVec.size() > 0)
    {
        for (iter = this->acceptclientVec.begin(); iter != acceptclientVec.end(); iter++)
        {
            if (((*iter)->acceptGetIP() == accept_ip) && ((*iter)->acceptGetPort() == accept_port))
            {
                ret = (*iter)->acceptGetRemainSpace();
                break;
            }
        }
    }  

    return ret;      
}

void tcpserver::AcceptConnection(uv_stream_t *server, int status)
{
    int32_t iret = 0;

    class tcpserver *tmpServer = (class tcpserver *)server->data;
    assert(tmpServer);

    if (status)
    {
        PlayerInfo("AcceptConnection ", status);
        return;
    }

    class acceptclient *tmpAccept = new acceptclient(tmpServer->loop, server, tmpServer->serverIP, tmpServer->serverPort);
    assert(tmpAccept);

    uv_mutex_lock(&tmpServer->acceptMutex);
    tmpServer->acceptclientVec.push_back(tmpAccept);
    uv_mutex_unlock(&tmpServer->acceptMutex);
    return;
}